package com.nit.lab.vote.service.vote.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nit.lab.vote.dto.system.TokenDTO;
import com.nit.lab.vote.dto.utils.OpResultDTO;
import com.nit.lab.vote.dto.utils.PagingDTO;
import com.nit.lab.vote.dto.utils.TableReqDTO;
import com.nit.lab.vote.dto.utils.TableRspDTO;
import com.nit.lab.vote.dto.vote.CandidateDTO;
import com.nit.lab.vote.dto.vote.ProjectDTO;
import com.nit.lab.vote.dto.vote.VoteDTO;
import com.nit.lab.vote.entity.vote.VoteEntity;
import com.nit.lab.vote.mapper.vote.CandidateMapper;
import com.nit.lab.vote.mapper.vote.ProjectMapper;
import com.nit.lab.vote.mapper.vote.VoteMapper;
import com.nit.lab.vote.service.vote.VoteService;
import com.nit.lab.vote.utils.JWTUtil;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class VoteServiceImpl implements VoteService {
    @Autowired(required = false)
    private VoteMapper voteMapper;
    @Autowired(required = false)
    private CandidateMapper candidateMapper;
    @Autowired(required = false)
    private ProjectMapper projectMapper;

    @Override
    public TableRspDTO logVote(TableReqDTO tableReqDTO) throws Exception {
        PagingDTO pagingDTO;
        Long count = voteMapper.countLogVote(
                tableReqDTO.parseQueryParam("projectName"),
                tableReqDTO.parseQueryParam("userName"),
                tableReqDTO.parseQueryParam("candidateName")
        );
        pagingDTO = new PagingDTO(
                tableReqDTO.getPageNo(),
                tableReqDTO.getPageSize(),
                count,
                voteMapper.listLogVote(
                        tableReqDTO.parseQueryParam("projectName"),
                        tableReqDTO.parseQueryParam("userName"),
                        tableReqDTO.parseQueryParam("candidateName"),
                        tableReqDTO.getStart(),
                        tableReqDTO.getPageSize(),
                        tableReqDTO.getSortField(),
                        tableReqDTO.getSortOrder()));
        return new TableRspDTO(pagingDTO);
    }

    @Override
    public TableRspDTO listAll(TableReqDTO tableReqDTO) throws Exception {
        String projectIdStr = tableReqDTO.parseQueryParam("projectId");
        PagingDTO pagingDTO;
        if (projectIdStr == null) {
            throw new IllegalArgumentException("Lose projectId");
        } else {
            Long projectId = Long.valueOf(projectIdStr);
            Long count = voteMapper.count4Table(
                    projectId,
                    tableReqDTO.parseQueryParam("userName"),
                    tableReqDTO.parseQueryParam("candidateName")
            );
            pagingDTO = new PagingDTO(
                    tableReqDTO.getPageNo(),
                    tableReqDTO.getPageSize(),
                    count,
                    voteMapper.list4Table(
                            projectId,
                            tableReqDTO.parseQueryParam("userName"),
                            tableReqDTO.parseQueryParam("candidateName"),
                            tableReqDTO.getStart(),
                            tableReqDTO.getPageSize(),
                            tableReqDTO.getSortField(),
                            tableReqDTO.getSortOrder()));
        }
        return new TableRspDTO(pagingDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OpResultDTO addList(String token, List<VoteDTO> voteDTOS) throws Exception {
        OpResultDTO op = new OpResultDTO();
        TokenDTO tokenDTO = JWTUtil.verifyToken(token);
        if (tokenDTO == null) {
            op.setMessage("error");
            op.setResult("用户信息有误");
        } else {
            if (tokenDTO.getRoleId() != 2) {
                op.setMessage("error");
                op.setResult("用户权限有误");
            } else {
                VoteEntity voteEntity;
                MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
                for (VoteDTO voteDTO : voteDTOS) {
                    voteEntity = mapperFactory.getMapperFacade().map(voteDTO, VoteEntity.class);
                    voteEntity.setGmtCreate(new Date(System.currentTimeMillis()));
                    voteEntity.setUserId(tokenDTO.getUserId());
                    voteMapper.updateUP(voteEntity);
                    voteMapper.add(voteEntity);
                }
            }
        }
        return op;
    }

    @Override
    public TableRspDTO listVote(TableReqDTO tableReqDTO) throws Exception {
        String projectIdStr = tableReqDTO.parseQueryParam("projectId");
        PagingDTO pagingDTO;
        if (projectIdStr == null) {
            throw new IllegalArgumentException("Lose projectId");
        } else {
            Long projectId = Long.valueOf(projectIdStr);
            List<CandidateDTO> candidateDTOS = candidateMapper.listByProject(
                    tableReqDTO.parseQueryParam("candidateName"),
                    tableReqDTO.parseQueryParam("dept"),
                    projectId,
                    tableReqDTO.getStart(),
                    tableReqDTO.getPageSize(),
                    tableReqDTO.getSortField(),
                    tableReqDTO.getSortOrder());
            Long count = candidateMapper.countByProject(
                    tableReqDTO.parseQueryParam("candidateName"),
                    tableReqDTO.parseQueryParam("dept"),
                    projectId);
            List<VoteDTO> ret = countVote(candidateDTOS, projectId);
            pagingDTO = new PagingDTO(
                    tableReqDTO.getPageNo(),
                    tableReqDTO.getPageSize(),
                    count,
                    ret



            );
        }
        return new TableRspDTO(pagingDTO);
    }

    @Override
    public TableRspDTO queryVoted(String token, TableReqDTO tableReqDTO) throws Exception {
        TokenDTO tokenDTO = JWTUtil.verifyToken(token);
        PagingDTO pagingDTO;
        Long count = voteMapper.countVoted();
        pagingDTO = new PagingDTO(
                tableReqDTO.getPageNo(),
                tableReqDTO.getPageSize(),
                count,
                voteMapper.queryVoted(
                        tableReqDTO.getStart(),
                        tableReqDTO.getPageSize(),
                        tableReqDTO.getSortField(),
                        tableReqDTO.getSortOrder()));
        return new TableRspDTO(pagingDTO);
    }

    @Override
    public TableRspDTO queryVoteResult(String token, TableReqDTO tableReqDTO) throws Exception {
        TokenDTO tokenDTO = JWTUtil.verifyToken(token);
        String projectIdStr = tableReqDTO.parseQueryParam("projectId");
        if (projectIdStr == null) {
            throw new IllegalArgumentException("Lose projectId");
        } else {
            Long projectId = Long.valueOf(projectIdStr);
            PagingDTO pagingDTO = new PagingDTO(
                    tableReqDTO.getPageNo(),
                    tableReqDTO.getPageSize(),
                    voteMapper.countVoteResult(tokenDTO.getUserId(), projectId),
                    voteMapper.queryVoteResult(
                            tokenDTO.getUserId(),
                            projectId,
                            tableReqDTO.getStart(),
                            tableReqDTO.getPageSize()
                    )
            );
            return new TableRspDTO(pagingDTO);
        }
    }

    @Override
    public List<VoteDTO> voteExcel(TableReqDTO tableReqDTO) throws Exception {
        return voteMapper.listLogVote(
                tableReqDTO.parseQueryParam("projectName"),
                tableReqDTO.parseQueryParam("userName"),
                tableReqDTO.parseQueryParam("candidateName"),
                1,
                65536,
                tableReqDTO.getSortField(),
                tableReqDTO.getSortOrder());
    }



    private static final Map<String, Integer> workMap = new HashMap<String, Integer>() {
        {
            put("国际领先", 0);
            put("国际先进", 1);
            put("国内领先", 2);
            put("国内先进", 3);
            put("国内一般", 4);
            put("其他", 5);
        }
    };

    private static final Map<String, Integer> subMap = new HashMap<String, Integer>() {
        {
            put("完全达到", 0);
            put("基本达到", 1);
            put("略有差距", 2);
            put("差距较大", 3);
        }
    };

    public List<VoteDTO> countVote(List<CandidateDTO> candidateDTOS, Long projectId) throws Exception {
        List<VoteDTO> ret = new ArrayList<>();
        ProjectDTO projectDTO = projectMapper.getProjectById(projectId);
        for (int i = 0; i < candidateDTOS.size(); i++) {
            CandidateDTO candidateDTO = candidateDTOS.get(i);
            List<VoteDTO> voteDTOS = voteMapper.listVote(candidateDTO.getCandidateId(), projectId);
            VoteDTO tmp = new VoteDTO();
            tmp.setKey((long) (i + 1));
            tmp.setCandidateName(candidateDTO.getCandidateName());
            tmp.setDept(candidateDTO.getDept());
            tmp.setProjectName(projectDTO.getProjectName());
            tmp.setSubject(candidateDTO.getSubject());
            tmp.setType(candidateDTO.getType());
            if (projectDTO.getProjectType() == 0) {
                Integer[] workInit = new Integer[6];
                Arrays.fill(workInit, 0);
                Integer[] subInit = new Integer[4];
                Arrays.fill(subInit, 0);
                tmp.setWorkTotal(workInit);
                tmp.setSubTotal(subInit);
                tmp.setCountPoint(voteDTOS.size());
                for (VoteDTO voteDTO : voteDTOS) {
                    tmp.getWorkTotal()[workMap.get(voteDTO.getWorkLevel())]++;
                    tmp.getSubTotal()[subMap.get(voteDTO.getSubLevel())]++;
                }
                ret.add(tmp);
            } else {
                Integer[] agreeInit = new Integer[3];
                Arrays.fill(agreeInit, 0);
                tmp.setAgreeTotal(agreeInit);
                tmp.setCountPoint(voteDTOS.size());
                for (VoteDTO voteDTO : voteDTOS) {
                    tmp.getAgreeTotal()[voteDTO.getAgree()]++;
                }
                ret.add(tmp);
            }
        }
        return ret;
    }
}
